home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / winsock / ircii2-6.zip / SRC\IRCII-2.6\SOURCE\HOOK.C < prev    next >
C/C++ Source or Header  |  1994-12-31  |  22KB  |  977 lines

  1. /*
  2.  * hook.c: Does those naughty hook functions. 
  3.  *
  4.  * Written By Michael Sandrof
  5.  *
  6.  * Copyright(c) 1990 
  7.  *
  8.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  9.  */
  10.  
  11. #ifndef lint
  12. static    char    rcsid[] = "@(#)$Id: hook.c,v 1.19 1994/10/09 06:39:35 mrg Stab $";
  13. #endif
  14.  
  15. #include "irc.h"
  16.  
  17. #include "hook.h"
  18. #include "vars.h"
  19. #include "ircaux.h"
  20. #include "alias.h"
  21. #include "list.h"
  22. #include "window.h"
  23. #include "server.h"
  24. #include "output.h"
  25. #include "edit.h"
  26.  
  27. #define SILENT 0
  28. #define QUIET 1
  29. #define NORMAL 2
  30. #define NOISY 3
  31.  
  32. /*
  33.  * The various ON levels: SILENT means the DISPLAY will be OFF and it will
  34.  * suppress the default action of the event, QUIET means the display will be
  35.  * OFF but the default action will still take place, NORMAL means you will be
  36.  * notified when an action takes place and the default action still occurs,
  37.  * NOISY means you are notified when an action occur plus you see the action
  38.  * in the display and the default actions still occurs 
  39.  */
  40. static    char    *noise_level[] = { "SILENT", "QUIET", "NORMAL", "NOISY" };
  41.  
  42. #define    HS_NOGENERIC    0x1000
  43. #define    HF_LOOKONLY    0x0001
  44. #define HF_NORECURSE    0x0002
  45. #define HF_GLOBAL    0x0004
  46.  
  47.     void    remove_hook();
  48. extern    int    load_depth;
  49.  
  50.     int    in_on_who = 0;
  51.  
  52.     NumericList *numeric_list = (NumericList *) 0;
  53. /* hook_functions: the list of all hook functions available */
  54.     HookFunc FAR hook_functions[] =
  55. {
  56.     { "ACTION",        (Hook *) 0,    3,    0,    0 },
  57.     { "CHANNEL_NICK",    (Hook *) 0,    3,    0,    0 },
  58.     { "CHANNEL_SIGNOFF",    (Hook *) 0,    3,    0,    0 },
  59.     { "CONNECT",        (Hook *) 0,    1,    0,    0 },
  60.     { "CTCP",        (Hook *) 0,    4,    0,    0 },
  61.     { "CTCP_REPLY",        (Hook *) 0,    3,    0,    0 },
  62.     { "DCC_CHAT",        (Hook *) 0,    2,    0,    0 },
  63.         { "DCC_CONNECT",        (Hook *) 0,     2,      0,      0 },
  64.         { "DCC_ERROR",          (Hook *) 0,     6,      0,      0 },
  65.         { "DCC_LOST",           (Hook *) 0,     2,      0,      0 },
  66.     { "DCC_RAW",        (Hook *) 0,    3,    0,    0 },
  67.         { "DCC_REQUEST",        (Hook *) 0,     4,      0,      0 },
  68.     { "DISCONNECT",        (Hook *) 0,    1,    0,    0 },
  69.         { "ENCRYPTED_NOTICE",   (Hook *) 0,     3,      0,      0 },
  70.         { "ENCRYPTED_PRIVMSG",  (Hook *) 0,     3,      0,      0 },
  71.     { "EXEC",        (Hook *) 0,    2,    0,    0 },
  72.     { "EXEC_ERRORS",    (Hook *) 0,    2,    0,    0 },
  73.     { "EXEC_EXIT",        (Hook *) 0,    3,    0,    0 },
  74.     { "EXEC_PROMPT",    (Hook *) 0,    2,    0,    0 },
  75.         { "EXIT",               (Hook *) 0,     1,      0,      0 },
  76.     { "FLOOD",        (Hook *) 0,    3,    0,    0 },
  77.     { "HELP",        (Hook *) 0,    2,    0,    0 },
  78.     { "HOOK",        (Hook *) 0,    1,    0,    0 },
  79.     { "IDLE",        (Hook *) 0,    1,    0,    0 },
  80.     { "INPUT",        (Hook *) 0,    1,    0,    0 },
  81.     { "INVITE",        (Hook *) 0,    2,    0,    0 },
  82.     { "JOIN",        (Hook *) 0,    2,    0,    0 },
  83.     { "LEAVE",        (Hook *) 0,    2,    0,    0 },
  84.     { "LIST",        (Hook *) 0,    3,    0,    HF_LOOKONLY },
  85.     { "MAIL",        (Hook *) 0,    2,    0,    0 },
  86.     { "MODE",        (Hook *) 0,    3,    0,    0 },
  87.     { "MSG",        (Hook *) 0,    2,    0,    0 },
  88.     { "MSG_GROUP",        (Hook *) 0,    3,    0,    0 },
  89.     { "NAMES",        (Hook *) 0,    2,    0,    HF_LOOKONLY },
  90.     { "NICKNAME",        (Hook *) 0,    2,    0,    0 },
  91.     { "NOTE",        (Hook *) 0,    10,    0,    0 },
  92.     { "NOTICE",        (Hook *) 0,    2,    0,    0 },
  93.     { "NOTIFY_SIGNOFF",    (Hook *) 0,    1,    0,    0 },
  94.     { "NOTIFY_SIGNON",    (Hook *) 0,    1,    0,    0 },
  95.     { "PUBLIC",        (Hook *) 0,    3,    0,    0 },
  96.     { "PUBLIC_MSG",        (Hook *) 0,    3,    0,    0 },
  97.     { "PUBLIC_NOTICE",    (Hook *) 0,    3,    0,    0 },
  98.     { "PUBLIC_OTHER",    (Hook *) 0,    3,    0,    0 },
  99.     { "RAW_IRC",        (Hook *) 0,    1,    0,    0 },
  100.     { "SEND_ACTION",    (Hook *) 0,    2,    0,    0 },
  101.     { "SEND_DCC_CHAT",    (Hook *) 0,    2,    0,    0 },
  102.     { "SEND_MSG",        (Hook *) 0,    2,    0,    0 },
  103.     { "SEND_NOTICE",    (Hook *) 0,    2,    0,    0 },
  104.     { "SEND_PUBLIC",    (Hook *) 0,    2,    0,    0 },
  105.     { "SEND_TALK",        (Hook *) 0,    2,    0,    0 },
  106.     { "SERVER_NOTICE",    (Hook *) 0,    1,    0,    0 },
  107.     { "SIGNOFF",        (Hook *) 0,    1,    0,    0 },
  108.     { "TALK",        (Hook *) 0,    2,    0,    0 },
  109.     { "TIMER",        (Hook *) 0,    1,    0,    0 },
  110.     { "TOPIC",        (Hook *) 0,    2,    0,    0 },
  111.     { "WALL",        (Hook *) 0,    2,    0,    HF_LOOKONLY },
  112.     { "WALLOP",        (Hook *) 0,    3,    0,    HF_LOOKONLY },
  113.     { "WHO",        (Hook *) 0,    6,    0,    HF_LOOKONLY },
  114.     { "WIDELIST",        (Hook *) 0,    1,    0,    HF_LOOKONLY },
  115.     { "WINDOW",        (Hook *) 0,    2,    0,    HF_NORECURSE },
  116.     { "WINDOW_KILL",    (Hook *) 0,    1,    0,    0 },
  117. #ifdef ON_KICK
  118.     { "KICK",        (Hook *) 0,    3,    0,    HF_LOOKONLY }
  119. #endif /* ON_KICK */
  120. };
  121.  
  122. int
  123. BelongsToServer(item)
  124.     Hook    *item;
  125. {
  126.     if (item->server == -1 || from_server ==
  127.             (item->server & ~HS_NOGENERIC))
  128.         return 1;
  129.     else
  130.         return 0;
  131. }
  132.  
  133. char    *
  134. fill_it_out(str, params)
  135.     char    *str;
  136.     int    params;
  137. {
  138.     define_big_buffer(buffer);
  139.     char    *arg,
  140.         *free_ptr = (char *) 0,
  141.         *ptr;
  142.     int    i = 0;
  143.  
  144.     malloc_strcpy(&free_ptr, str);
  145.     ptr = free_ptr;
  146.     *buffer = (char) 0;
  147.     while ((arg = next_arg(ptr, &ptr)) != NULL)
  148.     {
  149.         if (*buffer)
  150.             strmcat(buffer, " ", BIG_BUFFER_SIZE);
  151.         strmcat(buffer, arg, BIG_BUFFER_SIZE);
  152.         if (++i == params)
  153.             break;
  154.     }
  155.     for (; i < params; i++)
  156.         strmcat(buffer, (i < params-1) ? " %" : " *", BIG_BUFFER_SIZE);
  157.     if (*ptr)
  158.     {
  159.         strmcat(buffer, " ", BIG_BUFFER_SIZE);
  160.         strmcat(buffer, ptr, BIG_BUFFER_SIZE);
  161.     }
  162.     malloc_strcpy(&free_ptr, buffer);
  163.     free_big_buffer(buffer);
  164.     return (free_ptr);
  165. }
  166.  
  167.  
  168. /*
  169.  * A variety of comparison functions used by the hook routines follow.
  170.  */
  171.  
  172. struct    CmpInfoStruc
  173. {
  174.     int    ServerRequired;
  175.     int    SkipSerialNum;
  176.     int    SerialNumber;
  177.     int    Flags;
  178. }    cmp_info;
  179.  
  180. #define    CIF_NOSERNUM    0x0001
  181. #define    CIF_SKIP    0x0002
  182.  
  183. int     cmpinfodone = 0;
  184.  
  185. void
  186. setup_struct(ServReq, SkipSer, SerNum, flags)
  187.     int    ServReq;
  188.     int    SkipSer;
  189.     int    SerNum;
  190.     int    flags;
  191. {
  192.     cmp_info.ServerRequired = ServReq;
  193.     cmp_info.SkipSerialNum = SkipSer;
  194.     cmp_info.SerialNumber = SerNum;
  195.     cmp_info.Flags = flags;
  196. }
  197.  
  198. static    int
  199. Add_Remove_Check(Item, Name)
  200.     Hook    *Item;
  201.     char    *Name;
  202. {
  203.     int    comp;
  204.  
  205.     if (cmp_info.SerialNumber != Item->sernum)
  206.         return (Item->sernum > cmp_info.SerialNumber) ? 1 : -1;
  207.     if ((comp = my_stricmp(Item->nick, Name)) != 0)
  208.             return comp;
  209.     if (Item->server != cmp_info.ServerRequired)
  210.         return (Item->server > cmp_info.ServerRequired) ? 1 : -1;
  211.     return 0;
  212. }
  213.  
  214. static    void
  215. add_numeric_hook(numeric, nick, stuff, noisy, not, server, sernum)
  216.     int    numeric;
  217.     char    *nick,
  218.         *stuff;
  219.     int    noisy,
  220.         not;
  221.     int    server,
  222.         sernum;
  223. {
  224.     NumericList *entry;
  225.     Hook    *new;
  226.     char    buf[4];
  227.  
  228.     sprintf(buf, "%3.3u", numeric);
  229.     if ((entry = (NumericList *) find_in_list(&numeric_list, buf, 0)) ==
  230.             (NumericList *) 0)
  231.     {
  232.         entry = (NumericList *) new_malloc(sizeof(NumericList));
  233.         entry->name = (char *) 0;
  234.         entry->list = (Hook *) 0;
  235.         malloc_strcpy(&(entry->name), buf);
  236.         add_to_list(&numeric_list, entry);
  237.     }
  238.  
  239.     setup_struct((server==-1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
  240.     if ((new = (Hook *) remove_from_list_ext(&(entry->list), nick, Add_Remove_Check)) != NULL)
  241.     {
  242.         new->not = 1;
  243.         new_free(&(new->nick));
  244.         new_free(&(new->stuff));
  245.         wait_new_free(&new);
  246.     }
  247.     new = (Hook *) new_malloc(sizeof(Hook));
  248.     new->nick = (char *) 0;
  249.     new->noisy = noisy;
  250.     new->server = server;
  251.     new->sernum = sernum;
  252.     new->not = not;
  253.     new->global = loading_global;
  254.     new->stuff = (char *) 0;
  255.     malloc_strcpy(&new->nick, nick);
  256.     malloc_strcpy(&new->stuff, stuff);
  257.     upper(new->nick);
  258.     add_to_list_ext(&(entry->list), new, Add_Remove_Check);
  259. }
  260.  
  261. /*
  262.  * add_hook: Given an index into the hook_functions array, this adds a new
  263.  * entry to the list as specified by the rest of the parameters.  The new
  264.  * entry is added in alphabetical order (by nick). 
  265.  */
  266. static    void
  267. add_hook(which, nick, stuff, noisy, not, server, sernum)
  268.     int    which;
  269.     char    *nick,
  270.         *stuff;
  271.     int    noisy,
  272.         not;
  273.     int    server,
  274.         sernum;
  275. {
  276.     Hook    *new;
  277.  
  278.     if (which < 0)
  279.     {
  280.         add_numeric_hook(-which, nick, stuff, noisy, not, server,
  281.             sernum);
  282.         return;
  283.     }
  284.     setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
  285.     if ((new = (Hook *) remove_from_list_ext(&(hook_functions[which].list), nick, Add_Remove_Check)) != NULL)
  286.     {
  287.         new->not = 1;
  288.         new_free(&(new->nick));
  289.         new_free(&(new->stuff));
  290.         wait_new_free(&new);
  291.     }
  292.     new = (Hook *) new_malloc(sizeof(Hook));
  293.     new->nick = (char *) 0;
  294.     new->noisy = noisy;
  295.     new->server = server;
  296.     new->sernum = sernum;
  297.     new->not = not;
  298.     new->stuff = (char *) 0;
  299.     new->global = loading_global;
  300.     malloc_strcpy(&new->nick, nick);
  301.     malloc_strcpy(&new->stuff, stuff);
  302.     upper(new->nick);
  303.     add_to_list_ext(&(hook_functions[which].list), new, Add_Remove_Check);
  304. }
  305.  
  306. /* show_hook shows a single hook */
  307. extern    void
  308. show_hook(list, name)
  309.     Hook    *list;
  310.     char    *name;
  311. {
  312.     if (list->server != -1)
  313.         say("On %s from \"%s\" do %s [%s] <%d> (Server %d)%s",
  314.             name, list->nick,
  315.             (list->not ? "nothing" : list->stuff),
  316.             noise_level[list->noisy], list->sernum,
  317.             list->server&~HS_NOGENERIC,
  318.             (list->server&HS_NOGENERIC) ? " Exclusive" : empty_string);
  319.     else
  320.         say("On %s from \"%s\" do %s [%s] <%d>",
  321.             name, list->nick,
  322.             (list->not ? "nothing" : list->stuff),
  323.             noise_level[list->noisy],
  324.             list->sernum);
  325. }
  326.  
  327. /*
  328.  * show_numeric_list: If numeric is 0, then all numeric lists are displayed.
  329.  * If numeric is non-zero, then that particular list is displayed.  The total
  330.  * number of entries displayed is returned 
  331.  */
  332. static    int
  333. show_numeric_list(numeric)
  334.     int    numeric;
  335. {
  336.     NumericList *tmp;
  337.     Hook    *list;
  338.     char    buf[4];
  339.     int    cnt = 0;
  340.  
  341.     if (numeric)
  342.     {
  343.         sprintf(buf, "%3.3u", numeric);
  344.         if ((tmp = (NumericList *) find_in_list(&numeric_list, buf, 0))
  345.                 != NULL)
  346.         {
  347.             for (list = tmp->list; list; list = list->next, cnt++)
  348.                 show_hook(list, tmp->name);
  349.         }
  350.     }
  351.     else
  352.     {
  353.         for (tmp = numeric_list; tmp; tmp = tmp->next)
  354.         {
  355.             for (list = tmp->list; list; list = list->next, cnt++)
  356.                 show_hook(list, tmp->name);
  357.         }
  358.     }
  359.     return (cnt);
  360. }
  361.  
  362. /*
  363.  * show_list: Displays the contents of the list specified by the index into
  364.  * the hook_functions array.  This function returns the number of entries in
  365.  * the list displayed 
  366.  */
  367. static    int
  368. show_list(which)
  369.     int    which;
  370. {
  371.     Hook    *list;
  372.     int    cnt = 0;
  373.  
  374.     /* Less garbage when issueing /on without args. (lynx) */
  375.     for (list = hook_functions[which].list; list; list = list->next, cnt++)
  376.         show_hook(list, hook_functions[which].name);
  377.     return (cnt);
  378. }
  379.  
  380. /*
  381.  * do_hook: This is what gets called whenever a MSG, INVITES, WALL, (you get
  382.  * the idea) occurs.  The nick is looked up in the appropriate list. If a
  383.  * match is found, the stuff field from that entry in the list is treated as
  384.  * if it were a command. First it gets expanded as though it were an alias
  385.  * (with the args parameter used as the arguments to the alias).  After it
  386.  * gets expanded, it gets parsed as a command.  This will return as its value
  387.  * the value of the noisy field of the found entry, or -1 if not found. 
  388.  */
  389. /* huh-huh.. this sucks.. im going to re-write it so that it works */
  390. /*VARARGS*/
  391. int
  392. #ifdef USE_STDARG_H
  393. do_hook(int which, char *format, ...)
  394. {
  395.     va_list vl;
  396. #else
  397. do_hook(which, format, arg1, arg2, arg3, arg4, arg5, arg6)
  398.     int    which;
  399.     char    *format;
  400.     char    *arg1,
  401.         *arg2,
  402.         *arg3,
  403.         *arg4,
  404.         *arg5,
  405.         *arg6;
  406. {
  407. #endif
  408.     Hook    *tmp, **list;
  409.     define_big_buffer(buffer);
  410.     char    *name = (char *) 0;
  411.     int    RetVal = 1;
  412.     unsigned int    display;
  413.     int    i,
  414.         old_in_on_who;
  415.     Hook    **hook_array;
  416.     int    hook_num = 0;
  417.     static    int hook_level = 0;
  418.  
  419.     hook_array = (Hook **) malloc(sizeof(Hook *) * 2048);
  420.     hook_level++;
  421.     bzero(buffer, sizeof(buffer));
  422.  
  423. #ifdef USE_STDARG_H
  424.     va_start(vl, format);
  425.     vsprintf(buffer, format, vl);
  426.     va_end(vl);
  427. #else
  428.     sprintf(buffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
  429. #endif
  430.     if (which < 0)
  431.     {
  432.         NumericList *hook;
  433.         char    foo[4];
  434.  
  435.         sprintf(foo, "%3.3u", -which);
  436.         if ((hook = (NumericList *) find_in_list(&numeric_list, foo, 0))
  437.                 != NULL)
  438.         {
  439.             name = hook->name;
  440.             list = &hook->list;
  441.         }
  442.         else
  443.             list = (Hook **) 0;
  444.     }
  445.     else
  446.     {
  447.         if (hook_functions[which].mark && (hook_functions[which].flags & HF_NORECURSE))
  448.             list = (Hook **) 0;
  449.         else
  450.         {
  451.             list = &(hook_functions[which].list);
  452.             name = hook_functions[which].name;
  453.         }
  454.     }
  455.     if (!list)
  456.         return really_free(--hook_level), 1;
  457.  
  458.     if (which >= 0)
  459.         hook_functions[which].mark++;
  460.             /* not attached, so dont "fix" it */
  461.     {
  462.     int currser = 0, oldser = 0;
  463.     int currmatch = 0, oldmatch = 0;
  464.     Hook *bestmatch = (Hook *) 0;
  465.     int nomorethisserial = 0;
  466.  
  467.     for (tmp = *list;tmp;tmp = tmp->next)
  468.     {
  469.         currser = tmp->sernum;
  470.         if (currser != oldser)      /* new serial number */
  471.         {
  472.                         oldser = currser;
  473.             currmatch = oldmatch = nomorethisserial = 0;
  474.             if (bestmatch)
  475.                 hook_array[hook_num++] = bestmatch;
  476.             bestmatch = (Hook *) 0;
  477.         }
  478.  
  479.         if (nomorethisserial) 
  480.             continue;
  481.             /* if there is a specific server
  482.                hook and it doesnt match, then
  483.                we make sure nothing from
  484.                this serial number gets hooked */
  485.         if ((tmp->server != -1) &&
  486.            (tmp->server & HS_NOGENERIC) &&
  487.            (tmp->server != (from_server & HS_NOGENERIC)))
  488.         {
  489.             nomorethisserial = 1;
  490.             bestmatch = (Hook *) 0;
  491.                         continue;
  492.     }
  493.         currmatch = wild_match(tmp->nick,buffer);
  494.         if (currmatch > oldmatch)
  495.         {
  496.             oldmatch = currmatch;
  497.             bestmatch = tmp;
  498.         }
  499.     }
  500.         if (bestmatch)
  501.                 hook_array[hook_num++] = bestmatch;
  502.     }
  503.  
  504.     for (i = 0; i < hook_num; i++)
  505.     {
  506.         tmp = hook_array[i];
  507.         if (!tmp)
  508.         {
  509.             if (which >= 0)
  510.                 hook_functions[which].mark--;
  511.             return really_free(--hook_level), RetVal;
  512.         }
  513.         if (tmp->not)
  514.             continue;
  515.         send_text_flag = which;
  516.         if (tmp->noisy > QUIET)
  517.             say("%s activated by \"%s\"", name, buffer);
  518.         display = window_display;
  519.         if (tmp->noisy < NOISY)
  520.             window_display = 0;
  521.  
  522.         save_message_from();
  523.         old_in_on_who = in_on_who;
  524.         if (which == WHO_LIST || (which <= -311 && which >= -318))
  525.             in_on_who = 1;
  526.         {         /* This isnt attached to the if, so
  527.                    dont "fix" it */
  528.             int    len = strlen(tmp->stuff) + 1; 
  529.             char    *foo = new_malloc(len);
  530.  
  531.             bcopy(tmp->stuff, foo, len);
  532.             parse_line((char *) 0, foo, buffer, 0, 0);
  533.             new_free(&foo);
  534.         }
  535.         in_on_who = old_in_on_who;
  536.         window_display = display;
  537.         send_text_flag = -1;
  538.         restore_message_from();
  539.         if (!tmp->noisy && !tmp->sernum)
  540.             RetVal = 0;
  541.     }
  542.     if (which >= 0)
  543.         hook_functions[which].mark--;
  544.     free_big_buffer(buffer);
  545.     new_free(&hook_array);
  546.     return really_free(--hook_level), RetVal;
  547. }
  548.  
  549. static    void
  550. remove_numeric_hook(numeric, nick, server, sernum, quiet)
  551.     int    numeric;
  552.     char    *nick;
  553.     int    server;
  554.     int    sernum;
  555.     int    quiet;
  556. {
  557.     NumericList *hook;
  558.     Hook    *tmp,
  559.         *next;
  560.     char    buf[4];
  561.  
  562.     sprintf(buf, "%3.3u", numeric);
  563.     if ((hook = (NumericList *) find_in_list(&numeric_list, buf,0)) != NULL)
  564.     {
  565.         if (nick)
  566.         {
  567.             setup_struct((server == -1) ? -1 :
  568.                 (server & ~HS_NOGENERIC), sernum - 1, sernum, 0);
  569.             if ((tmp = (Hook *) remove_from_list(&(hook->list),
  570.                     nick)) != NULL)
  571.             {
  572.                 if (!quiet)
  573.                     say("\"%s\" removed from %s list",
  574.                         nick, buf);
  575.                 tmp->not = 1;
  576.                 new_free(&(tmp->nick));
  577.                 new_free(&(tmp->stuff));
  578.                 wait_new_free(&tmp);
  579.                 if (hook->list == (Hook *) 0)
  580.                 {
  581.                     if ((hook = (NumericList *)
  582.                         remove_from_list(&numeric_list,
  583.                         buf)) != NULL)
  584.                     {
  585.                         new_free(&(hook->name));
  586.                         new_free(&hook);
  587.                     }
  588.                 }
  589.                 return;
  590.             }
  591.         }
  592.         else
  593.         {
  594.             for(tmp = hook->list; tmp; tmp = next)
  595.             {
  596.                 next = tmp->next;
  597.                 tmp->not = 1;
  598.                 new_free(&(tmp->nick));
  599.                 new_free(&(tmp->stuff));
  600.                 wait_new_free(&tmp);
  601.             }
  602.             hook->list = (Hook *) 0;
  603.             if (!quiet)
  604.                 say("The %s list is empty", buf);
  605.             return;
  606.         }
  607.     }
  608.     if (quiet)
  609.         return;
  610.     if (nick)
  611.         say("\"%s\" is not on the %s list", nick, buf);
  612.     else
  613.         say("The %s list is empty", buf);
  614. }
  615.  
  616. extern  void    flush_on_hooks()
  617. {
  618.         int x;
  619.         int old_display = window_display;
  620.         
  621.         window_display = 0;
  622.         for (x=100;x<999;x++)
  623.                 remove_numeric_hook(x, (char *) 0, 1, x, 0);
  624.         for (x=0;x<NUMBER_OF_LISTS;x++)
  625.                 remove_hook(x, (char *) 0, 1, x, 0);
  626.         window_display = old_display;
  627. }
  628.  
  629. extern    void
  630. remove_hook(which, nick, server, sernum, quiet)
  631.     int    which;
  632.     char    *nick;
  633.     int    server,
  634.         sernum,
  635.         quiet;
  636. {
  637.     Hook    *tmp,
  638.         *next;
  639.  
  640.     if (which < 0)
  641.     {
  642.         remove_numeric_hook(-which, nick, server, sernum, quiet);
  643.         return;
  644.     }
  645.     if (nick)
  646.     {
  647.         setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC),
  648.             sernum-1, sernum, 0);
  649.         if ((tmp = (Hook *)
  650.             remove_from_list_ext(&(hook_functions[which].list),
  651.             nick, Add_Remove_Check)) != NULL)
  652.         {
  653.             if (!quiet)
  654.                 say("\"%s\" removed from %s list", nick,
  655.                     hook_functions[which].name);
  656.             tmp->not = 1;
  657.             new_free(&(tmp->nick));
  658.             new_free(&(tmp->stuff));
  659.             wait_new_free(&tmp);
  660.         }
  661.         else if (!quiet)
  662.             say("\"%s\" is not on the %s list", nick,
  663.                     hook_functions[which].name);
  664.     }
  665.     else
  666.     {
  667.         for(tmp = hook_functions[which].list; tmp; tmp=next)
  668.         {
  669.             next = tmp->next;
  670.             tmp->not = 1;
  671.             new_free(&(tmp->nick));
  672.             new_free(&(tmp->stuff));
  673.             wait_new_free(&tmp);
  674.         }
  675.         hook_functions[which].list = (Hook *) 0;
  676.         if (!quiet)
  677.             say("The %s list is empty", hook_functions[which].name);
  678.     }
  679. }
  680.  
  681. /* on: The ON command */
  682. /*ARGSUSED*/
  683. void
  684. on(command, args)
  685.     char    *command,
  686.         *args;
  687. {
  688.     char    *func,
  689.     *nick,
  690.     *serial;
  691.     /* int noisy = NORMAL, not = 0, remove = 0, -not used */
  692.     int    noisy,
  693.         not,
  694.         server,
  695.         sernum,
  696.         remove,
  697.         len,
  698.         which = 0,
  699.         cnt,
  700.         i;
  701.  
  702.     if (get_int_var(NOVICE_VAR) && !load_depth)
  703.     {
  704.         yell("*** You may not type ON commands when you have the NOVICE");
  705.         yell("*** variable set to ON. Some ON commands may cause a");
  706.         yell("*** security breach on your machine, or enable another");
  707.         yell("*** user to control your IRC session. Read the help files");
  708.         yell("*** in /HELP ON before using ON");
  709.         return;
  710.     }
  711.     if ((func = next_arg(args, &args)) != NULL)
  712.     {
  713.         if (*func == '#')
  714.         {
  715.             if (!(serial = next_arg(args, &args)))
  716.             {
  717.                 say("No serial number specified");
  718.                 return;
  719.             }
  720.             sernum = atoi(serial);
  721.             func++;
  722.         }
  723.         else
  724.             sernum = 0;
  725.         switch (*func)
  726.         {
  727.         case '&':
  728.             server = from_server;
  729.             func++;
  730.             break;
  731.         case '@':
  732.             server = from_server|HS_NOGENERIC;
  733.             func++;
  734.             break;
  735.         default:
  736.             server = -1;
  737.             break;
  738.         }
  739.         switch (*func)
  740.         {
  741.         case '-':
  742.             noisy = QUIET;
  743.             func++;
  744.             break;
  745.         case '^':
  746.             noisy = SILENT;
  747.             func++;
  748.             break;
  749.         case '+':
  750.             noisy = NOISY;
  751.             func++;
  752.             break;
  753.         default:
  754.             noisy = NORMAL;
  755.             break;
  756.         }
  757.         if ((len = strlen(func)) == 0)
  758.         {
  759.             say("You must specify an event type!");
  760.             return;
  761.         }
  762.         for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
  763.         {
  764.             if (!my_strnicmp(func, hook_functions[i].name, len))
  765.             {
  766.                 if (strlen(hook_functions[i].name) == len)
  767.                 {
  768.                     cnt = 1;
  769.                     which = i;
  770.                     break;
  771.                 }
  772.                 else
  773.                 {
  774.                     cnt++;
  775.                     which = i;
  776.                 }
  777.             }
  778.             else if (cnt)
  779.                 break;
  780.         }
  781.         if (cnt == 0)
  782.         {
  783.             if (is_number(func))
  784.             {
  785.                 which = atoi(func);
  786.                 if ((which < 0) || (which > 999))
  787.                 {
  788.                     say("Numerics must be between 001 and 999");
  789.                     return;
  790.                 }
  791.                 which = -which;
  792.             }
  793.             else
  794.             {
  795.                 say("No such ON function: %s", func);
  796.                 return;
  797.             }
  798.         }
  799.         else if (cnt > 1)
  800.         {
  801.             say("Ambiguous ON function: %s", func);
  802.             return;
  803.         }
  804.         else 
  805.         {
  806.             if (get_int_var(INPUT_PROTECTION_VAR) &&
  807.                     !my_strnicmp(hook_functions[which].name,
  808.                     "INPUT", 5))
  809.             {
  810.     say("You cannot use /ON INPUT with INPUT_PROTECTION set");
  811.     say("Please read /HELP ON INPUT, and /HELP SET INPUT_PROTECTION");
  812.     return;
  813.             }
  814.         }
  815.         remove = 0;
  816.         not = 0;
  817.         switch (*args)
  818.         {
  819.         case '-':
  820.             remove = 1;
  821.             args++;
  822.             break;
  823.         case '^':
  824.             not = 1;
  825.             args++;
  826.             break;
  827.         }
  828.         if ((nick = new_next_arg(args, &args)) != NULL)
  829.         {
  830.             if (which < 0)
  831.                 nick = fill_it_out(nick, 1);
  832.             else
  833.                 nick = fill_it_out(nick,
  834.                     hook_functions[which].params);
  835.             if (remove)
  836.             {
  837.                 if (strlen(nick) == 0)
  838.                     say("No expression specified");
  839.                 else
  840.                     remove_hook(which, nick, server,
  841.                         sernum, 0);
  842.             }
  843.             else
  844.  
  845.     /* Indent this bit back a couple of tabs - phone */
  846.  
  847.     {
  848.         if (not)
  849.             args = empty_string;
  850.         if (*nick)
  851.         {
  852.             if (*args == LEFT_BRACE)
  853.             {
  854.                 char    *ptr = MatchingBracket(++args,
  855.                         LEFT_BRACE, RIGHT_BRACE);
  856.                 if (!ptr)
  857.                 {
  858.                     say("Unmatched brace in ON");
  859.                     new_free(&nick);
  860.                     return;
  861.                 }
  862.                 else if (ptr[1])
  863.                 {
  864.                     say("Junk after closing brace in ON");
  865.                     new_free(&nick);
  866.                     return;
  867.                 }
  868.                 else
  869.                     *ptr = '\0';
  870.             }
  871.             add_hook(which, nick, args, noisy, not, server, sernum);
  872.             if (which < 0)
  873.                 say("On %3.3u from \"%s\" do %s [%s] <%d>",
  874.                     -which, nick, (not ? "nothing" : args),
  875.                     noise_level[noisy], sernum);
  876.             else
  877.                 say("On %s from \"%s\" do %s [%s] <%d>",
  878.                     hook_functions[which].name, nick,
  879.                     (not ? "nothing" : args),
  880.                     noise_level[noisy], sernum);
  881.             new_free(&nick);
  882.         }
  883.     }
  884.     /* End of doovie intentation */
  885.         }
  886.         else
  887.         {
  888.             if (remove)
  889.                 remove_hook(which, (char *) 0, server,
  890.                     sernum, 0);
  891.             else
  892.             {
  893.                 if (which < 0)
  894.                 {
  895.                     if (show_numeric_list(-which) == 0)
  896.                         say("The %3.3u list is empty.",
  897.                             -which);
  898.                 }
  899.                 else if (show_list(which) == 0)
  900.                     say("The %s list is empty.",
  901.                         hook_functions[which].name);
  902.             }
  903.         }
  904.     }
  905.     else
  906.     {
  907.         int    total = 0;
  908.  
  909.         say("ON listings:");
  910.         for (which = 0; which < NUMBER_OF_LISTS; which++)
  911.             total += show_list(which);
  912.         total += show_numeric_list(0);
  913.         if (total == 0)
  914.             say("All ON lists are empty.");
  915.     }
  916. }
  917.  
  918. static    void
  919. write_hook(fp, hook, name)
  920.     FILE    *fp;
  921.     Hook    *hook;
  922.     char    *name;
  923. {
  924.     char    *stuff = (char *) 0;
  925.  
  926.     if (hook->server!=-1)
  927.         return;
  928.     switch (hook->noisy)
  929.     {
  930.     case SILENT:
  931.         stuff = "^";
  932.         break;
  933.     case QUIET:
  934.         stuff = "-";
  935.         break;
  936.     case NORMAL:
  937.         stuff = empty_string;
  938.         break;
  939.     case NOISY:
  940.         stuff = "+";
  941.         break;
  942.     }
  943.     if (hook->sernum)
  944.         fprintf(fp, "ON #%s%s %d \"%s\"", stuff, name, hook->sernum,
  945.             hook->nick);
  946.     else
  947.         fprintf(fp, "ON %s%s \"%s\"", stuff, name, hook->nick);
  948.     fprintf(fp, " %s\n", hook->stuff);
  949. }
  950.  
  951. /*
  952.  * save_hooks: for use by the SAVE command to write the hooks to a file so it
  953.  * can be interpreted by the LOAD command 
  954.  */
  955. void
  956. save_hooks(fp, do_all)
  957.     FILE    *fp;
  958.     int    do_all;
  959. {
  960.     Hook    *list;
  961.     NumericList *numeric;
  962.     int    which;
  963.  
  964.     for (which = 0; which < NUMBER_OF_LISTS; which++)
  965.     {
  966.         for (list = hook_functions[which].list; list; list = list->next)
  967.             if (!list->global || do_all)
  968.                 write_hook(fp,list, hook_functions[which].name);
  969.     }
  970.     for (numeric = numeric_list; numeric; numeric = numeric->next)
  971.     {
  972.         for (list = numeric->list; list; list = list->next)
  973.             if (!list->global)
  974.                 write_hook(fp, list, numeric->name);
  975.     }
  976. }
  977.